package x.trident.core.micro.gateway.core.filters.factory.base;

import cn.hutool.core.util.StrUtil;
import x.trident.core.micro.gateway.config.properties.TridentGatewayProperties;
import x.trident.core.micro.gateway.modular.cache.ResourceRedisCache;
import x.trident.core.micro.gateway.modular.validate.TokenService;
import x.trident.core.auth.api.SessionManagerApi;
import x.trident.core.micro.api.exception.MicroException;
import x.trident.core.micro.api.exception.enums.GatewayExceptionEnum;
import x.trident.core.scanner.api.pojo.resource.ResourceDefinition;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;

import javax.annotation.Resource;

/**
 * 权限相关网关过滤器，因为过滤器在使用时候不加参数，所以AbstractGatewayFilterFactory没有写泛型
 *
 * @author Seven
 * @date 2021/5/12 22:20
 */
@SuppressWarnings("all")
public abstract class BaseGatewayFilterFactory extends AbstractGatewayFilterFactory {

    @Resource
    private TokenService tokenService;

    @Resource
    private SessionManagerApi sessionManagerApi;

    @Resource
    private ResourceRedisCache resourceRedisCache;

    @Resource
    private TridentGatewayProperties tridentGatewayProperties;

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {

            // 当前请求的路径
            ServerHttpRequest request = exchange.getRequest();
            String currentRequestPath = request.getPath().toString();

            // 请求token
            String token = tokenService.getToken(request);

            // 如果token不为空，则先判断是否登录过期了，过期了就直接打回，不过期不做处理
            if (StrUtil.isNotBlank(token)) {

                // 校验token是否正确
                tokenService.validateToken(token);

                // 校验通过后，刷新用户的session的过期时间
                sessionManagerApi.refreshSession(token);
            }

            // 根据url获取资源详情
            ResourceDefinition resourceDefinition = resourceRedisCache.get(currentRequestPath);

            // 找不到对应的资源，如果开启了严格过滤模式，则打回请求
            if (resourceDefinition == null && tridentGatewayProperties.getStrictFiltering()) {
                throw new MicroException(GatewayExceptionEnum.CACHE_URL_NULL);
            }

            // 找不到请求的资源，并且没开启严格过滤模式，则直接通过请求
            else if (resourceDefinition == null && !tridentGatewayProperties.getStrictFiltering()) {
                return chain.filter(exchange.mutate().request(request).build());
            }

            // 权限相关校验
            this.validateAuth(token, resourceDefinition);

            return chain.filter(exchange.mutate().request(request).build());
        };
    }

    /**
     * 真正权限校验过程
     *
     * @author Seven
     * @date 2021/5/12 22:38
     */
    public abstract void validateAuth(String token, ResourceDefinition resourceDefinition);

}
